﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InHD.model;
using System.Reflection;
using InHD.utilities;
using System.Data;
using System.Collections.ObjectModel;

namespace InHD.dataaccess
{
    class StaffRepository
    {        
        #region Fields

        readonly ObservableCollection<Staff> _staffs;
        //For DB Utils
        private DBUltils _db;
        string[] _paramName;
        object[] _value;
        DBUltils.ParamType[] _paramType;
        #endregion // Fields

        #region Constructor

        /// <summary>
        /// Creates a new repository of Staffs.
        /// </summary>
        public StaffRepository()
        {
            _staffs = new ObservableCollection<Staff>();
            this._db = new DBUltils();
            if (!_db.connectDB(Constants.Security.DefaultDBUser, Constants.Security.DefaultDBPassword))
                throw new ArgumentNullException(Constants.Messages.CannotConnectDB);
        }

        #endregion // Constructor

        #region Public Interface

        /// <summary>
        /// Raised when a Staff is placed into the repository.
        /// </summary>
        public event EventHandler<StaffAddedEventArgs> StaffAdded;

        /// <summary>
        /// Places the specified Staff into the repository.
        /// If the Staff is already in the repository, an
        /// exception is not thrown.
        /// </summary>
        public string AddStaff(Staff Staff)
        {
            try
            {
                if (Staff == null)
                    throw new ArgumentNullException("Staff");
                for (int i = 0; i < this._staffs.Count; i++)
                {
                    if (this._staffs[i].StaffCode.Equals(Staff.StaffCode))
                    {
                        return "DuplicateCode";
                    }
                }

                if (!_staffs.Contains(Staff))
                {
                    //// Add new company info into database
                    if (_db == null)
                        throw new ArgumentNullException(Constants.Messages.DBNotInitialized);
                    Staff.StaffUNK = "Sta - " + Guid.NewGuid().ToString();
                    _paramName = new string[]{"@staffUNK",
                                        "@staffCode",
                                        "@name",
                                        "@address",
                                        "@phone",
                                        "@email",
                                        "@lastAccess",
                                        "@staffType",
                                        "@userName",
                                        "@passWord"
                };
                    _paramType = new DBUltils.ParamType[]{DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.NStr,
                                                    DBUltils.ParamType.LNStr,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.DateTime,
                                                    DBUltils.ParamType.Int,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.Str
                                                    };
                    _value = new object[]{Staff.StaffUNK,
                                      Staff.StaffCode,
                                      Staff.Fullname,
                                      (Staff.Address == null) ? string.Empty : Staff.Address,
                                      (Staff.Phone == null) ? string.Empty : Staff.Phone,
                                      (Staff.Email == null) ? string.Empty : Staff.Email,
                                      DateTime.Today.ToString(),
                                      Staff.SType,
                                      Staff.Username,
                                      (Staff.Password == null) ? "1" : Staff.Password
                                    };

                    _db.queryDB(Constants.StoreProcedures.Staff.AddStaff, _paramName, _paramType, _value, DBUltils.QueryType.Insert);
                    _staffs.Add(Staff);

                    if (this.StaffAdded != null)
                        this.StaffAdded(this, new StaffAddedEventArgs(Staff));
                }
            }
            catch (Exception e)
            {
                Logger.RecordMessage(e, MessageType.Error);
                return e.Message;
            }
            return string.Empty;
        }


        public string EditStaff(Staff staff)
        {
            try
            {
                if (staff == null)
                    throw new ArgumentNullException("company");

                //// edit existing product which have customerUNK  == customer.customerUNK
                for (int i = 0; i < this._staffs.Count; i++)
                {
                    if (this._staffs[i].StaffUNK.Equals(staff.StaffUNK))
                    {
                        for (int j = 0; j < this._staffs.Count; j++)
                        {
                            if ((i != j) && this._staffs[j].StaffCode.Equals(staff.StaffCode))
                            {
                                return "DuplicateCode";
                            }
                        }
                        this._staffs[i] = staff;
                        if (_db == null)
                            throw new ArgumentNullException(Constants.Messages.DBNotInitialized);
                        _paramName = new string[]{"@staffUNK",
                                        "@staffCode",
                                        "@name",
                                        "@address",
                                        "@phone",
                                        "@email",
                                        "@lastAccess",
                                        "@staffType",
                                        "@userName",
                                        "@passWord"
                };
                        _paramType = new DBUltils.ParamType[]{DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.NStr,
                                                    DBUltils.ParamType.LNStr,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.DateTime,
                                                    DBUltils.ParamType.Int,
                                                    DBUltils.ParamType.Str,
                                                    DBUltils.ParamType.Str
                                                    };
                        _value = new object[]{staff.StaffUNK,
                                      staff.StaffCode,
                                      staff.Fullname,
                                      (staff.Address == null) ? string.Empty : staff.Address,
                                      (staff.Phone == null) ? string.Empty : staff.Phone,
                                      (staff.Email == null) ? string.Empty : staff.Email,
                                      DateTime.Today.ToString(),
                                      staff.SType,
                                      staff.Username,
                                      (staff.Password == null) ? "1" : staff.Password
                                    };

                        _db.queryDB(Constants.StoreProcedures.Staff.UpdateStaff, _paramName, _paramType, _value, DBUltils.QueryType.Update);
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }

            return string.Empty;
        }

        public string DeleteStaff(string UNK)
        {
            bool found = false;
            foreach (Staff staff in this._staffs)
            {
                if (staff.StaffUNK.Equals(UNK))
                {
                    this._staffs.Remove(staff);
                    found = true;
                    break;
                }
            }
            if (!found)
                return "UNK is not exist";
            try
            {
                if (_db == null)
                    throw new ArgumentNullException(Constants.Messages.DBNotInitialized);
                if (UNK == null)
                    throw new ArgumentNullException("Null Unique key");
                _paramName = new string[] { "@staffUNK" };
                _paramType = new DBUltils.ParamType[] { DBUltils.ParamType.Str };
                _value = new string[] { UNK };

                _db.queryDB(Constants.StoreProcedures.Staff.DeleteStaff, _paramName, _paramType, _value, DBUltils.QueryType.Delete);
            }
            catch (Exception e)
            {
                Logger.RecordMessage(e, MessageType.Error);
                return e.Message;
            }
            //System.Windows.MessageBox.Show("Delete Staff successfully!!!");
            return string.Empty;
        }

        /// <summary>
        /// Returns a shallow-copied list of all Staffs in the repository.
        /// </summary>
        public ObservableCollection<Staff> GetStaffs()
        {
            return new ObservableCollection<Staff>(_staffs);
        }

        /// <summary>
        /// Kiem tra user co ton tai trong he thong hay khong
        /// </summary>
        /// <param name="_cstaff">bien kieu Staff de kiem tra</param>
        /// <returns>ID cua user neu tim thay, nguoc lai tra ve -1</returns>
        public string IsUsernameExisting(ref Staff _cstaff)
        {
            foreach (Staff s in this._staffs)
            {
                if (s.Username.Equals(_cstaff.Username) && s.Password.Equals(_cstaff.Password))
                {
                    _cstaff = s;
                    _cstaff.LastAccess = System.DateTime.Now;
                    //// Goi method update LastAccess cho user nay
                    return s.StaffUNK;
                }
            }

            return string.Empty;
        }


        /// <summary>
        /// Connect vao Database de lay toan bo du lieu ve cac User hien co trong he thong
        /// </summary>
        public string LoadAllStaffs()
        {
            //// Load all staff from database
            try
            {
                if (_db == null)
                    throw new ArgumentNullException(Constants.Messages.DBNotInitialized);
                _paramName = new string[] { };
                _paramType = new DBUltils.ParamType[] { };
                _value = new string[] { };
                DataSet ds = _db.queryDB(Constants.StoreProcedures.Staff.GetAllStaffs, _paramName, _paramType, _value, DBUltils.QueryType.Select);

                foreach (DataRow r in ds.Tables[0].Rows)
                {
                    Staff staff = Staff.CreateStaff((StaffTypes)Convert.ToInt32(r["staffType"]),
                                                    Convert.ToString(r["userName"]),
                                                    Convert.ToString(r["name"]),
                                                    Convert.ToString(r["passWord"]),
                                                    Convert.ToString(r["address"]),
                                                    Convert.ToString(r["email"]),
                                                    Convert.ToString(r["phone"]),
                                                    Convert.ToString(r["staffCode"]),
                                                    Convert.ToString(r["staffUNK"]));
                    this._staffs.Add(staff);
                }
            }
            catch (Exception e)
            {
                Logger.RecordMessage(e, MessageType.Error);
                return e.Message;
            }
            return string.Empty;
        }

        public List<Staff> GetStaffsWthSearchCriteria(string property, string criteria)
        {
            List<Staff> tmpList = new List<Staff>();
            foreach (Staff pro in this._staffs)
            {
                Type t = pro.GetType();
                PropertyInfo p = t.GetProperty(property);
                string valueOfProperty = (string)p.GetValue(pro, null);
                if (valueOfProperty.Contains(criteria))
                {
                    tmpList.Add(pro);
                }
            }

            return tmpList;
        }

        #endregion // Public Interface

        #region Private Helpers

        #endregion // Private Helpers



        public List<Staff> GetProductsWthSearchCriteria(string property, string criteria)
        {
            List<Staff> tmpList = new List<Staff>();
            foreach (Staff pro in this._staffs)
            {
                Type t = pro.GetType();
                PropertyInfo p = t.GetProperty(property);
                string valueOfProperty = (string)p.GetValue(pro, null);
                if (valueOfProperty.ToUpper().Contains(criteria.ToUpper()))
                {
                    tmpList.Add(pro);
                }
            }

            return tmpList;
        }
    }
}
